/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package saltocaballo.expertos;

import java.awt.Component;
import java.util.*;
import javax.swing.JPanel;
import saltocaballo.comunes.Configuracion;
import saltocaballo.comunes.constantes;
import saltocaballo.entidades.Casilla;
import saltocaballo.entidades.Tablero;

/**
 *
 * @author Martinoxs
 */
public class movimientosCaballo {
    
    Configuracion conf;
    
    public movimientosCaballo(){
        conf = Configuracion.getInstancia();
    }
    
    /**
     * 
     * Método que verifica que la casilla elegida no haya sido visitada y en L a la casilla anterior
     * 
     * @param casilla casilla elegida como próximo movimiento
     * @param casillas todas las casillas del tablero
     * @return true casilla válida
     */
    public boolean esCasillaValida(Casilla casilla,Casilla casillaAnterior, String tamanioTablero) {
        if (casilla.fueVisitada() || casilla.tieneObstaculo()){
            return false;
        } else {
            if (casillaAnterior != null){
                
                int filaCasilla = Integer.parseInt(casilla.getCoordenada().substring(0,1));
                int columnaCasilla = Integer.parseInt(casilla.getCoordenada().substring(2,3));
                int filaCasillaAnterior = Integer.parseInt(casillaAnterior.getCoordenada().substring(0,1));
                int columnaCasillaAnterior = Integer.parseInt(casillaAnterior.getCoordenada().substring(2,3));
                
                int columnasTablero = Integer.parseInt(tamanioTablero.substring(0,1));
                int filasTablero = Integer.parseInt(tamanioTablero.substring(2,3));
                
                //restriccion horizontal
                if (filaCasilla == filaCasillaAnterior) return false;
                
                //restriccion vertical
                if (columnaCasilla == columnaCasillaAnterior) return false;
                
                //restriccion diagonal
                String coordenadaCasilla = casilla.getCoordenada();
                String coordenadaCasillaAnterior = casillaAnterior.getCoordenada();
                
//                System.out.println("Casilla: " + coordenadaCasilla);
//                System.out.println("CasillaAnterior: " + coordenadaCasillaAnterior);
                
                for(int i = 0; i < filasTablero; i++){
                    if(coordenadaCasilla.equals(String.valueOf(filaCasillaAnterior + i) + ";" + String.valueOf(columnaCasillaAnterior + i))) return false;
                    if(coordenadaCasilla.equals(String.valueOf(filaCasillaAnterior - i) + ";" + String.valueOf(columnaCasillaAnterior - i))) return false;
                }
                for(int j = 0; j < columnasTablero; j++){
                    if(coordenadaCasilla.equals(String.valueOf(filaCasillaAnterior + j) + ";" + String.valueOf(columnaCasillaAnterior + j))) return false;
                    if(coordenadaCasilla.equals(String.valueOf(filaCasillaAnterior - j) + ";" + String.valueOf(columnaCasillaAnterior - j))) return false;
                }
                
                for(int i = 0; i < filasTablero; i++){
                    if(coordenadaCasilla.equals(String.valueOf(filaCasillaAnterior + i) + ";" + String.valueOf(columnaCasillaAnterior - i))) return false;
                    if(coordenadaCasilla.equals(String.valueOf(filaCasillaAnterior - i) + ";" + String.valueOf(columnaCasillaAnterior + i))) return false;
                }
                for(int j = 0; j < columnasTablero; j++){
                    if(coordenadaCasilla.equals(String.valueOf(filaCasillaAnterior + j) + ";" + String.valueOf(columnaCasillaAnterior - j))) return false;
                    if(coordenadaCasilla.equals(String.valueOf(filaCasillaAnterior - j) + ";" + String.valueOf(columnaCasillaAnterior + j))) return false;
                }
                 
                //restriccion L
                if (filaCasilla > (filaCasillaAnterior + 2)
                        || filaCasilla < (filaCasillaAnterior - 2)
                        || columnaCasilla > (columnaCasillaAnterior + 2)
                        || columnaCasilla < (columnaCasillaAnterior - 2)){
                    return false;
                }
                
                return true;
            } else {
                return true;
            }
        }
    }
    
    /**
     * Método que devuelve sólo los movimientos permitidos de los 8 posibles
     * @param casilla Coordenada (x;y) de la casilla
     * @param tablero Tablero de juego generado
     * @return Lista de coordenadas de casillas válidas
     */
    public List<String> getMovimientosValidos(String casilla, Tablero tab, JPanel pan){
        Tablero tablero = tab;
        JPanel panel = pan;
        
        List<String> movimientos = getMovimientos(casilla);
        
        //Elimino casillas con posiciones en negativo
        int fila;
        int columna;
        List<String> casillasEliminar = new ArrayList<String>();
        
        for(String mov: movimientos){
            fila = getFila(mov);
            columna = getColumna(mov);
            if (fila < 0 || columna < 0) casillasEliminar.add(mov);
        }
        
        for (String mov: casillasEliminar){
            movimientos.remove(mov);
        }
        
        //Elimino movimientos fuera de los límites
        casillasEliminar = new ArrayList<String>();
        for(String mov: movimientos){
            if(getFila(mov) > (tablero.getCantFilas() - 1)) casillasEliminar.add(mov);
            if(getColumna(mov) > (tablero.getCantColumnas() - 1)) casillasEliminar.add(mov);
        }
        
        for (String mov: casillasEliminar){
            movimientos.remove(mov);
        }
        
        //Elimino casillas visitadas y ocupadas
        casillasEliminar = new ArrayList<String>();
        for(Component comp: panel.getComponents()){
            if (comp.getClass().equals(Casilla.class)){
                Casilla c = (Casilla) comp;
                if (movimientos.contains(c.getCoordenada())){
                    if (c.fueVisitada() || c.tieneObstaculo() || c.tieneCaballo()) casillasEliminar.add(c.getCoordenada());
                }
            }
        }
        
        for (String mov: casillasEliminar){
            movimientos.remove(mov);
        }
        
        return movimientos;
    }
    
    /**
     * Método que devuelve todas las casillas válidas sin restricciones
     * @param coordenada Coordenada (x;y) de la casilla
     * @return Lista con coordendas de los 8 posibles movimientos
     */
    private List<String> getMovimientos(String coordenada){
        int fila = getFila(coordenada);
        int columna = getColumna(coordenada);
        
        List<String> movimientos = new ArrayList<String>();
        
        movimientos.add((fila + 2) + ";" + (columna + 1));
        movimientos.add((fila + 2) + ";" + (columna - 1));
        movimientos.add((fila + 1) + ";" + (columna + 2));
        movimientos.add((fila + 1) + ";" + (columna - 2));
        movimientos.add((fila - 2) + ";" + (columna + 1));
        movimientos.add((fila - 2) + ";" + (columna - 1));
        movimientos.add((fila - 1) + ";" + (columna + 2));
        movimientos.add((fila - 1) + ";" + (columna - 2));
        
        return movimientos;
    }
    
    private int getFila(String casilla){
        String[] coords = casilla.split(";");
        return Integer.parseInt(coords[0]);
    }
    
    private int getColumna(String casilla){
        String[] coords = casilla.split(";");
        return Integer.parseInt(coords[1]);
    }
    
    /**
     * Método que devuelve los movimientos ordenados según los métodos MVR o Grado
     * 
     * @param movimientos lista de movimientos a ordenar
     * @param tablero tablero de referencia
     * @param panel panel donde se encuentre el tablero (uso interno)
     * @param orden método MVR o Grado
     * @return 
     */
    public List<String> ordenarMovimientos(List<String> movimientos, Tablero tablero, JPanel panel, String orden){
        List<String> listaRdo = new ArrayList<String>();
        Map<String, Integer> casillas = new HashMap<String, Integer>();
        
        for(String casilla: movimientos){
            casillas.put(casilla, getMovimientosValidos(casilla, tablero, panel).size());
        }
        
        Map<String,Integer> mapOrdenado = new HashMap<String, Integer>();
        
        if(!orden.equals(constantes.sinHeuristica)){
            mapOrdenado = sortByComparator(casillas, orden);
        } else {
            for(Map.Entry<String, Integer> c: casillas.entrySet()){
                mapOrdenado.put(c.getKey(), c.getValue());
            }
        }
        
        for (String casilla : mapOrdenado.keySet()) {
            listaRdo.add(casilla);
        }
        
        return listaRdo;
    }
    
    /**
     * Comparador usado por el método ordenarMovimientos
     * 
     * @param unsortMap
     * @param metodo
     * @return 
     */
    private static Map sortByComparator(Map unsortMap, String metodo) {
 
        List list = new LinkedList(unsortMap.entrySet());
 
        if (metodo.equals(constantes.casillaMenosRestringida)){
            Collections.sort(list, new Comparator() {
                public int compare(Object o1, Object o2) {
                    return ((Comparable) ((Map.Entry) (o2)).getValue()).compareTo(((Map.Entry) (o1)).getValue());
                }
            });
        } else {
            Collections.sort(list, new Comparator() {
                public int compare(Object o1, Object o2) {
                    return ((Comparable) ((Map.Entry) (o1)).getValue()).compareTo(((Map.Entry) (o2)).getValue());
                }
            });
        }
 
        //put sorted list into map again
	Map sortedMap = new LinkedHashMap();
	for (Iterator it = list.iterator(); it.hasNext();) {
	     Map.Entry entry = (Map.Entry)it.next();
	     sortedMap.put(entry.getKey(), entry.getValue());
	}
	return sortedMap;
   }
}
